using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using Volo.Abp.DependencyInjection;
using TenantManagementService.Monitoring;

namespace TenantManagementService.HttpApi.Middleware
{
    /// <summary>
    /// Prometheus 指标收集中间件
    /// </summary>
    public class PrometheusMetricsMiddleware : IMiddleware, ITransientDependency
    {
        private readonly PrometheusMetricsService _prometheusMetricsService;
        private readonly ILogger<PrometheusMetricsMiddleware> _logger;

        public PrometheusMetricsMiddleware(
            PrometheusMetricsService prometheusMetricsService,
            ILogger<PrometheusMetricsMiddleware> logger)
        {
            _prometheusMetricsService = prometheusMetricsService;
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            var stopwatch = Stopwatch.StartNew();
            var requestData = ExtractRequestData(context);

            try
            {
                await next(context);
            }
            catch (Exception ex)
            {
                RecordErrorMetrics(requestData, ex);
                throw;
            }
            finally
            {
                stopwatch.Stop();
                RecordRequestMetrics(requestData, stopwatch.ElapsedMilliseconds, context.Response.StatusCode);
            }
        }

        private RequestData ExtractRequestData(HttpContext context)
        {
            var request = context.Request;
            var labels = new Dictionary<string, string>();

            // HTTP 方法
            labels["method"] = request.Method;

            // HTTP 状态码（将在请求完成后设置）
            var statusCode = 200;

            // API 端点路径
            labels["endpoint"] = GetEndpointPath(request.Path);

            // 协议版本
            labels["protocol"] = request.Protocol;

            // User-Agent
            if (request.Headers.TryGetValue("User-Agent", out var userAgent))
            {
                labels["user_agent"] = TruncateString(userAgent.ToString(), 100);
            }

            // 租户信息（如果可用）
            var tenantId = GetTenantId(context);
            if (tenantId.HasValue)
            {
                labels["tenant_id"] = tenantId.Value.ToString();
            }

            return new RequestData
            {
                Labels = labels,
                Method = request.Method,
                Path = request.Path,
                QueryString = request.QueryString.ToString(),
                StartTime = DateTime.UtcNow
            };
        }

        private void RecordRequestMetrics(RequestData requestData, long durationMs, int statusCode)
        {
            try
            {
                // 更新标签包含状态码
                var labels = new Dictionary<string, string>(requestData.Labels)
                {
                    ["status_code"] = statusCode.ToString(),
                    ["status_class"] = GetStatusCodeClass(statusCode)
                };

                // 记录请求总数
                _prometheusMetricsService.Increment("http_requests_total", labels);

                // 记录请求持续时间（转换为秒）
                _prometheusMetricsService.RecordHistogram(
                    "http_request_duration_seconds",
                    durationMs / 1000.0,
                    labels);

                // 记录活跃请求
                _prometheusMetricsService.Decrement("http_requests_active");

                // 记录请求大小（如果可用）
                RecordRequestSizeMetrics(requestData, labels);

                // 记录响应大小（如果可用）
                // 注意：这里需要在 RequestData 中添加响应大小信息

                // 记录服务运行时间
                var uptime = DateTime.UtcNow.Subtract(Process.GetCurrentProcess().StartTime).TotalSeconds;
                _prometheusMetricsService.RecordGauge("process_uptime_seconds", uptime);

                // 记录内存使用情况
                RecordMemoryMetrics();

                _logger.LogDebug("记录 HTTP 请求指标: {Method} {Path} - {StatusCode} - {DurationMs}ms",
                    requestData.Method, requestData.Path, statusCode, durationMs);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录 HTTP 请求指标失败");
            }
        }

        private void RecordErrorMetrics(RequestData requestData, Exception exception)
        {
            try
            {
                var labels = new Dictionary<string, string>(requestData.Labels)
                {
                    ["exception_type"] = exception.GetType().Name,
                    ["status_code"] = "500",
                    ["status_class"] = "5xx"
                };

                // 记录错误总数
                _prometheusMetricsService.Increment("http_errors_total", labels);

                // 记录异常类型
                _prometheusMetricsService.Increment("http_exceptions_total", new Dictionary<string, string>
                {
                    ["exception_type"] = exception.GetType().Name,
                    ["method"] = requestData.Method,
                    ["endpoint"] = GetEndpointPath(requestData.Path)
                });

                // 记录活跃请求（减少）
                _prometheusMetricsService.Decrement("http_requests_active");

                _logger.LogInformation("记录 HTTP 错误指标: {Method} {Path} - {ExceptionType}",
                    requestData.Method, requestData.Path, exception.GetType().Name);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录 HTTP 错误指标失败");
            }
        }

        private void RecordRequestSizeMetrics(RequestData requestData, Dictionary<string, string> labels)
        {
            try
            {
                if (requestData.ContentLength > 0)
                {
                    _prometheusMetricsService.RecordHistogram(
                        "http_request_size_bytes",
                        requestData.ContentLength,
                        labels);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录请求大小指标失败");
            }
        }

        private void RecordMemoryMetrics()
        {
            try
            {
                var process = Process.GetCurrentProcess();

                // 内存使用量（字节）
                _prometheusMetricsService.RecordGauge(
                    "process_memory_usage_bytes",
                    process.WorkingSet64);

                // 虚拟内存使用量（字节）
                _prometheusMetricsService.RecordGauge(
                    "process_virtual_memory_bytes",
                    process.VirtualMemorySize64);

                // GC 信息
                _prometheusMetricsService.RecordGauge(
                    "dotnet_gc_memory_total_bytes",
                    GC.GetTotalMemory(false));

                // GC 代数
                for (int i = 0; i <= GC.MaxGeneration; i++)
                {
                    _prometheusMetricsService.RecordGauge(
                        "dotnet_gc_collections_total",
                        GC.CollectionCount(i),
                        new Dictionary<string, string> { ["generation"] = i.ToString() });
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录内存指标失败");
            }
        }

        private static string GetEndpointPath(string path)
        {
            // 将路径参数替换为占位符，避免指标维度爆炸
            if (string.IsNullOrEmpty(path))
                return "/";

            // 替换常见的 ID 参数
            var normalizedPath = path;
            normalizedPath = System.Text.RegularExpressions.Regex.Replace(normalizedPath, @"/\d+", "/{id}");
            normalizedPath = System.Text.RegularExpressions.Regex.Replace(normalizedPath, @"/[a-f0-9-]{36}", "/{guid}");
            normalizedPath = System.Text.RegularExpressions.Regex.Replace(normalizedPath, @"/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", "/{guid}");

            return normalizedPath;
        }

        private static string GetStatusCodeClass(int statusCode)
        {
            return statusCode switch
            {
                >= 200 and < 300 => "2xx",
                >= 300 and < 400 => "3xx",
                >= 400 and < 500 => "4xx",
                >= 500 and < 600 => "5xx",
                _ => "unknown"
            };
        }

        private static Guid? GetTenantId(HttpContext context)
        {
            // 尝试从不同的来源获取租户 ID
            if (context.Request.Headers.TryGetValue("X-Tenant-Id", out var tenantIdHeader) &&
                Guid.TryParse(tenantIdHeader, out var tenantId))
            {
                return tenantId;
            }

            if (context.Request.Query.TryGetValue("tenantId", out var tenantIdQuery) &&
                Guid.TryParse(tenantIdQuery, out var queryTenantId))
            {
                return queryTenantId;
            }

            // 从 ABP 的当前租户获取
            if (context.RequestServices != null)
            {
                var currentTenant = context.RequestServices.GetService<Volo.Abp.MultiTenancy.ICurrentTenant>();
                if (currentTenant?.IsAvailable == true)
                {
                    return currentTenant.Id;
                }
            }

            return null;
        }

        private static string TruncateString(string value, int maxLength)
        {
            return value?.Length > maxLength ? value.Substring(0, maxLength) : value ?? string.Empty;
        }

        private class RequestData
        {
            public Dictionary<string, string> Labels { get; set; } = new();
            public string Method { get; set; } = string.Empty;
            public string Path { get; set; } = string.Empty;
            public string QueryString { get; set; } = string.Empty;
            public long ContentLength { get; set; }
            public DateTime StartTime { get; set; }
        }
    }
}